# python实现
# nextPts,status,err = cv.calcOpticalFlowPyrLK(prevlmg,nextlmg,prevPts,nextPts[,status[,err[,winSize[,maxLevel[,criteria[,flags[,minEigThreshold]]]]]]]]])
# prevlmg，第一帧图像。
# nextlmg, 第二帧图像。
# prevPts, 第一帧图像中的所有特征点向量
# status, 输出状态向量；如果相应点光流被发现，向量的每个元素被设置为1，否则，设置为0
# 找到好的特征点
# goodFeaturesToTrack(ImputArray_image,OutputArray_corners,maxCorners,qualityLevel,minDistance,InputArray_mask,blockSize,harrisK)

import numpy as np
import cv2 as cv
import time
import datetime
import matplotlib.pyplot as plt

#读取图像
videoFileName = r'vtest.avi'
cap = cv.VideoCapture(videoFileName)

fourcc = cv.VideoWriter_fourcc(*'XVID')                                                                      #设置保存图片的格式
out = cv.VideoWriter(datetime.datetime.now().strftime("%A_%d_%B_%Y_%I_%M_%S%p")+'.avi',fourcc,10,(768,576))  #分辨率和原视频对应

#角点检测参数
feature_params = dict( maxCorners = 100,
                       qualityLevel = 0.3,
                       minDistance = 7,
                       blockSize = 7)
#lucas-kanade光流法参数
lk_params = dict( winSize = (15,15),
                  maxLevel = 2,
                  criteria = (cv.TERM_CRITERIA_EPS|cv.TERM_CRITERIA_COUNT,10,0.03))

#计算第一帧特征点
ret,prev = cap.read()
prevGray = cv.cvtColor(prev,cv.COLOR_BGR2GRAY)
p0 = cv.goodFeaturesToTrack(prevGray,mask = None,**feature_params)
while True:
    ret,frame = cap.read()
    if not ret:                   #没有读到当前帧，则结束
        break
    gray = cv.cvtColor(frame,cv.COLOR_BGR2GRAY)
    # 计算光流
    p1, st, err = cv.calcOpticalFlowPyrLK(prevGray,gray, p0, None, **lk_params)
    #选取好的跟踪点
    goodPoints = p1[st == 1]
    goodPrevPoints = p0[st == 1]
    #在结果图像中叠加画出特征点和计算出来的光流向量
    res = frame.copy()
    drawColor = (0,0,255)
    for i,(cur,prev) in enumerate(zip(goodPoints,goodPrevPoints)):
        x0,y0 = cur.ravel()
        x1,y1 = prev.ravel()
        cv.line(res,(x0,y0),(x1,y1),drawColor)
        cv.circle(res,(x0,y0),3,drawColor)
    #更新上一帧
    prevGray = gray.copy()
    p0 = goodPoints.reshape(-1,1,2)
    #显示计算结果图像
    cv.imshow('result',res)
    out.write(res)
    key = cv.waitKey(30)    #每一帧间隔30ms
    if key == 27:
        break
cv.destroyAllWindows()
cap.release()










